/********************************************************************

Encapsulate Glut framework into class GlControl.

Write Date: 2011/07/14
Author: Deng Nianchen
>>>> Encapsulate most of the glut callback functions include:
>>>> display function
>>>> key event functions
>>>> mouse event functions
>>>> reshape event functions
>>>> timer event functions

Modify Date: 2011/03/24
Author: Deng Nianchen
>>>> Add mainLoop () function (idle callback function)
>>>> Add to GlBase namespace
>>>> Use GlEvent to encapsulate event data

*********************************************************************/
#ifndef GLENV_H
#define GLENV_H
#include <Windows.h>
#include <gl/glut.h>
#include "OOPGl_BaseGlobal.hpp"
#include <ooputils/Singleton.hpp>
#include "GlEvent.hpp"

_GLBASE_BEGIN

/**************************************************************************************************
 * <summary>  Gl control. </summary>
 *
 * <remarks>  Deng Nianchen, 2011/3/18. </remarks>
 **************************************************************************************************/

class _EXPORT_GLBASE_CLASS GlApplication : public OOPUtils::Singleton< GlApplication >
{
	friend class OOPUtils::Singleton< GlApplication >;

private:

  int _timerDuration;
  GlPoint _windowSize;

public:

  GlApplication ();

  void initialize (int argc, char** argv);

  /**************************************************************************************************
   * <summary>  Creates a window. </summary>
   *
   * <remarks>  Deng Nianchen, 2011/7/14. </remarks>
   *
   * <param name="mode">          The mode. </param>
   * <param name="title">         The title. </param>
   * <param name="isFullScreen">  true if is full screen. </param>
   * <param name="width">         The width. </param>
   * <param name="height">        The height. </param>
   * <param name="posX">          The position x coordinate. </param>
   * <param name="posY">          The position y coordinate. </param>
   **************************************************************************************************/

  void createWindow (uint mode, const char* title, bool isFullScreen,
    int width = 800, int height = 600, int posX = 0, int posY = 0);
  void run ();

  virtual void initialEvent () {}
  virtual void drawEvent () {}

  /**************************************************************************************************
   * <summary>  Key press event. </summary>
   *
   * <remarks>  Deng Nianchen, 2011/7/14. </remarks>
   *
   * <param name="e"> The. </param>
   **************************************************************************************************/

  virtual void keyPressEvent (GlEvent e) {}

  /**************************************************************************************************
   * <summary>  Mouse event. </summary>
   *
   * <remarks>  Deng Nianchen, 2011/7/14. </remarks>
   *
   * <param name="e"> The. </param>
   **************************************************************************************************/

  virtual void mouseEvent (GlEvent e) {}

  /**************************************************************************************************
   * <summary>  Timer event. </summary>
   *
   * <remarks>  Deng Nianchen, 2011/7/14. </remarks>
   **************************************************************************************************/

  virtual void timerEvent () {}

  /**************************************************************************************************
   * <summary>  Main loop. </summary>
   *
   * <remarks>  Deng Nianchen, 2011/3/24. </remarks>
   **************************************************************************************************/

  virtual void mainLoop () {}

  /**************************************************************************************************
   * <summary>  Reshape window event. </summary>
   *
   * <remarks>  Deng Nianchen, 2011/7/14. </remarks>
   *
   * <param name="width">   The width. </param>
   * <param name="height">  The height. </param>
   **************************************************************************************************/

  virtual void reshapeWindowEvent (int width, int height)
  {
    _windowSize = GlPoint (width, height);
    glViewport (0, 0, width, height);
    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
    gluPerspective (45.0, (double)width / (double)height, 1.0, 200.0);
    glutPostRedisplay ();
  }

  /**************************************************************************************************
   * <summary>  Registers the timer described by millisecond. </summary>
   *
   * <remarks>  Deng Nianchen, 2011/7/14. </remarks>
   *
   * <param name="millisecond"> The millisecond. </param>
   **************************************************************************************************/

  void registerTimer (int millisecond = 0);

  /**************************************************************************************************
   * <summary>  Cancel timer. </summary>
   *
   * <remarks>  Deng Nianchen, 2011/7/14. </remarks>
   **************************************************************************************************/

  void cancelTimer () { _timerDuration = 0; }

  /**************************************************************************************************
   * <summary>  Queries if a timer is registered. </summary>
   *
   * <remarks>  Deng Nianchen, 2011/7/14. </remarks>
   *
   * <returns>  true if a timer is registered, false if not. </returns>
   **************************************************************************************************/

  bool isTimerRegistered () const { return _timerDuration > 0 ? true : false; }

  GlPoint getWindowSize () const { return _windowSize; }
};

_GLBASE_END

#endif